﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace NDF
{
    /// <summary>
    /// 静态辅助类，提供一组用于检查输入参数是否合规的工具方法。
    /// </summary>
    public static class Guard
    {
        /// <summary>
        /// 检查输入的参数是否为 Null，如果是，则抛出 <see cref="System.ArgumentNullException"/> 异常。
        /// </summary>
        /// <param name="paramValue">被校验的参数值。</param>
        /// <exception cref="System.ArgumentNullException">如果传入的参数 paramValue 值为 Null，则抛出该异常。</exception>
        public static void ArgumentNotNull(object paramValue)
        {
            if (paramValue == null)
            {
                throw new ArgumentNullException("传入的参数值不能为 Null。");
            }
        }

        /// <summary>
        /// 检查输入的参数是否为 Null，如果是，则抛出 <see cref="System.ArgumentNullException"/> 异常。
        /// </summary>
        /// <param name="paramValue">被校验的参数值。</param>
        /// <param name="paramName">被校验的参数名称。</param>
        /// <exception cref="System.ArgumentNullException">如果传入的参数 paramValue 值为 Null，则抛出该异常。</exception>
        public static void ArgumentNotNull(object paramValue, string paramName)
        {
            ArgumentNotNull(paramValue, paramName, string.Format("传入的参数 {0} 值不能为 Null。", paramName));
        }

        /// <summary>
        /// 检查输入的参数是否为 Null，如果是，则抛出 <see cref="System.ArgumentNullException"/> 异常。
        /// </summary>
        /// <param name="paramValue">被校验的参数值。</param>
        /// <param name="paramName">被校验的参数名称。</param>
        /// <param name="message">描述错误的消息。</param>
        /// <exception cref="System.ArgumentNullException">如果传入的参数 paramValue 值为 Null，则抛出该异常。</exception>
        public static void ArgumentNotNull(object paramValue, string paramName, string message)
        {
            if (paramValue == null)
            {
                throw new ArgumentNullException(paramName, message);
            }
        }


        /// <summary>
        /// 检查输入的参数是否为 Null、空或者空白字符串组成，如果是，则抛出 <see cref="System.ArgumentNullException"/> 异常。
        /// </summary>
        /// <param name="paramValue">被校验的 <see cref="System.String"/> 类型参数值。</param>
        /// <exception cref="System.ArgumentNullException">
        /// 如果传入的参数 paramValue 值为 Null、空或者空白字符串组成，则抛出该异常。
        /// </exception>
        public static void ArgumentNotNullOrWhiteSpace(string paramValue)
        {
            if (string.IsNullOrWhiteSpace(paramValue))
            {
                throw new ArgumentNullException("paramValue", "传入的参数值不能为 Null、空或者空白字符串。");
            }
        }

        /// <summary>
        /// 检查输入的参数是否为 Null、空或者空白字符串组成，如果是，则抛出 <see cref="System.ArgumentNullException"/> 异常。
        /// </summary>
        /// <param name="paramValue">被校验的 <see cref="System.String"/> 类型参数值。</param>
        /// <param name="paramName">被校验的参数名称。</param>
        /// <exception cref="System.ArgumentNullException">
        /// 如果传入的参数 paramValue 值为 Null、空或者空白字符串组成，则抛出该异常。
        /// </exception>
        public static void ArgumentNotNullOrWhiteSpace(string paramValue, string paramName)
        {
            ArgumentNotNullOrWhiteSpace(paramValue, paramName, string.Format("传入的参数 {0} 值不能为 Null、空或者空白字符串。", paramName));
        }

        /// <summary>
        /// 检查输入的参数是否为 Null、空或者空白字符串组成，如果是，则抛出 <see cref="System.ArgumentNullException"/> 异常。
        /// </summary>
        /// <param name="paramValue">被校验的 <see cref="System.String"/> 类型参数值。</param>
        /// <param name="paramName">被校验的参数名称。</param>
        /// <param name="message">描述错误的消息。</param>
        /// <exception cref="System.ArgumentNullException">
        /// 如果传入的参数 paramValue 值为 Null、空或者空白字符串组成，则抛出该异常。
        /// </exception>
        public static void ArgumentNotNullOrWhiteSpace(string paramValue, string paramName, string message)
        {
            if (string.IsNullOrWhiteSpace(paramValue))
            {
                throw new ArgumentNullException(message, paramName);
            }
        }



        /// <summary>
        /// 检查输入的参数是否不为 Null 且为指定的类型 <see cref="System.Type"/> 列表中的某一个类型。如果不是，则抛出 <see cref="System.ArgumentNullException"/> 或 <see cref="System.ArgumentException"/> 异常。
        /// </summary>
        /// <param name="paramValue">被校验的参数值。</param>
        /// <param name="types">待检查的类型 <see cref="System.Type"/> 列表。</param>
        /// <exception cref="System.ArgumentNullException">如果传入的参数 paramValue 为 Null，则抛出该异常。</exception>
        /// <exception cref="System.ArgumentException">
        /// 如果传入的参数 paramValue 的类型不属于列表 types 的任何一个类型，则抛出该异常。
        /// </exception>
        public static void ArgumentTypeOutRange(object paramValue, params Type[] types)
        {
            Guard.ArgumentNotNull(paramValue);
            var type = paramValue.GetType();
            foreach (var item in types)
            {
                if (type.IsAssignableFrom(item))
                {
                    return;
                }
            }
            string message = string.Format("传入的参数不属于\"{0}\"列表中的任何一个类型。", types);
            throw new ArgumentException(message);
        }

        /// <summary>
        /// 检查输入的参数是否不为 Null 且为指定的类型 <see cref="System.Type"/> 列表中的某一个类型。如果不是，则抛出 <see cref="System.ArgumentNullException"/> 或 <see cref="System.ArgumentException"/> 异常。
        /// </summary>
        /// <param name="paramValue">被校验的参数值。</param>
        /// <param name="paramName">被校验的参数名称。</param>
        /// <param name="types">待检查的类型 <see cref="System.Type"/> 列表。</param>
        /// <exception cref="System.ArgumentNullException">如果传入的参数 paramValue 为 Null，则抛出该异常。</exception>
        /// <exception cref="System.ArgumentException">
        /// 如果传入的参数 paramValue 的类型不属于列表 types 的任何一个类型，则抛出该异常。
        /// </exception>
        public static void ArgumentTypeOutRange(object paramValue, string paramName, params Type[] types)
        {
            Guard.ArgumentNotNull(paramValue, paramName);
            var type = paramValue.GetType();
            foreach (var item in types)
            {
                if (type.IsAssignableFrom(item))
                {
                    return;
                }
            }
            string message = string.Format("传入的参数\"{0}\"不属于\"{1}\"列表中的任何一个类型。", paramName, types);
            throw new ArgumentException(message, paramName);
        }
    }
}
